package net.boyandi.picback.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Random;

import at.fhj.utils.misc.ProgressTracker;

/**
 * @author Ilya Boyandin
 */
public final class Files {
    

    private Files() {
    }

    public static final String concatPathParts(String ... parts) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            sb.append(parts[i]);
            if (i < parts.length - 1  &&
                !parts[i].endsWith(File.separator)  &&
                !parts[i + 1].startsWith(File.separator)) {
                sb.append(File.separator);
            }
        }
        return sb.toString();
    }

    private static final String[] humanReadableSizeDesc = new String[] {
        "B", "K", "M", "G", "T"
    };
    private static final DecimalFormat humanReadableDecFmt = new DecimalFormat("0.#");
    
    public static String humanReadableSize(long size) {
        int k = 0;
        double dsize = size;
        while (size / 1024 > 0  &&  k < humanReadableSizeDesc.length) {
            size = size / 1024;
            dsize = dsize / 1024.0;
            k++;
        }
        
        return humanReadableDecFmt.format(dsize) + " " + humanReadableSizeDesc[k];
    }
    
    public static void copy(File srcFile, File destFile, ProgressTracker tracker) throws IOException {
        if (tracker.isCancelled()) return;
        FileInputStream in = null;
        FileOutputStream out = null;
        
        File tmpFile = createTempFileIn(destFile.getParent());
        
        try {
            final long size = srcFile.length();
            in = new FileInputStream(srcFile);
            out = new FileOutputStream(tmpFile);
            
            final byte[] buf = new byte[4096];
            int read;
            while ((read = in.read(buf)) >= 0) {
                out.write(buf, 0, read);
                if (tracker.isCancelled()) break;
                tracker.incTaskProgress(100.0 * read / size);
            }
        } finally {
            try {
                if (in != null) in.close();
            } catch (IOException ioe) {
                // there is nothing we can do if close fails
            }
            try {
                if (out != null) out.close();
            } catch (IOException ioe) {
                // there is nothing we can do if close fails
            }
        }
        if (tracker.isCancelled()) {
            tmpFile.delete();
        } else {
            File destBackup = null;
            if (destFile.exists()) {
                destBackup = createTempFileIn(destFile.getParent());
                destFile.renameTo(destBackup);
            }
            if (tmpFile.renameTo(destFile)) {
                if (destBackup != null) {
                    destBackup.delete();
                }
            } else {
                try {
                    tmpFile.delete();
                    destBackup.delete();
                } catch (Throwable th) {
                    // Ignore it: we will fail to cleanup, but won't spoil
                    // the original problem cause
                }
                throw new IOException("Couldn't rename temp file '" + tmpFile.getPath() + 
                        "' into the destination file '" + destFile.getPath() + "'");
                
            }
            tracker.taskCompleted();
        }
    }

    private static final Random random = new Random();
    
    private static final String randomFileName(String prefix, int length) {
        StringBuilder sb = new StringBuilder();
        sb.append(prefix);
        for (int i = 0; i < length; i++) {
            sb.append((char)('a' + random.nextInt(26)));
        }
        return sb.toString();
    }
    

    public static File createTempFileIn(String path) {
        File file;
        do { 
            String name = Files.concatPathParts(path, randomFileName(".piba_", 6));
            file = new File(name); 
        } while (file.exists());
        return file;
    }

}
